import { createNextAnimateFrameEvent, HasOwner } from "xbsj-base"
import { RotationEditing } from "."
import * as Cesium from 'cesium';
import { computeCzmModelMatrix, pickVirtualPlane, toCartesian } from "@czmSrc/utils";
import { ESJNativeNumber16 } from "earthsdk3";

export class BasePlane extends HasOwner<RotationEditing> {
    get viewer() { return this.owner.czmViewer.viewer as Cesium.Viewer; }
    get scene() { return this.viewer.scene as Cesium.Scene; }
    get sceneObject() { return this.owner; }
    protected _valid = false;
    get valid() { return this._valid; }
    protected _normal = new Cesium.Cartesian3(0, 0, 0);
    get normal() { return this._normal; }
    protected _origin = new Cesium.Cartesian3(0, 0, 0);
    get origin() { return this._valid && this._origin; }

    constructor(owner: RotationEditing) {
        super(owner)
    }
    /**
     * 获取鼠标点与平面之间的交点
     * @param windowPos 鼠标位置
     * @returns 
     */
    pick(windowPos: [number, number]) {
        if (!this.normal) return;
        if (!this.owner.cartesian) return;
        const planePivot = this.owner.cartesian;
        const windowCoordinates = toCartesian(windowPos);
        return pickVirtualPlane(this.scene, planePivot, this.normal, windowCoordinates);
    }
}

export class HeadingPlane extends BasePlane {
    constructor(owner: RotationEditing) {
        super(owner);
        {
            const update = () => {
                const modelMatrix = computeCzmModelMatrix({
                    position: this.sceneObject.position,
                    rotation: this.sceneObject.rotation
                });
                this._valid = !!modelMatrix;
                if (!modelMatrix) return;
                this._origin.x = modelMatrix[4];
                this._origin.y = modelMatrix[5];
                this._origin.z = modelMatrix[6];

                this._normal.x = modelMatrix[8];
                this._normal.y = modelMatrix[9];
                this._normal.z = modelMatrix[10];
            }
            update();
            const event = this.ad(createNextAnimateFrameEvent(
                this.sceneObject.positionChanged,
                this.sceneObject.rotationChanged,
            ))
            this.ad(event.don(update));
        }
    }
}

export class PitchPlane extends BasePlane {
    constructor(owner: RotationEditing) {
        super(owner);

        const update = () => {
            const rm = computeCzmModelMatrix({
                rotation: [this.sceneObject.selfRotation[0], 0, 0],
            });
            if (!rm) {
                throw new Error('PitchPlane: rm is undefined');
            };
            const m = computeCzmModelMatrix({
                position: this.sceneObject.position,
                rotation: this.sceneObject.rotation,
                localModelMatrix: Cesium.Matrix4.toArray(rm) as ESJNativeNumber16,
            });
            this._valid = !!m;
            if (!m) return;
            {
                const v = this._normal;
                v.x = -m[0];
                v.y = -m[1];
                v.z = -m[2];
            }
            {
                const v = this._origin;
                v.x = m[4];
                v.y = m[5];
                v.z = m[6];
            }
        };
        update();
        this.dispose(this.sceneObject.positionChanged.disposableOn(update));
        this.dispose(this.sceneObject.rotationChanged.disposableOn(update));
        this.dispose(this.sceneObject.selfRotationChanged.disposableOn(update));
    }
}

export class RollPlane extends BasePlane {
    constructor(owner: RotationEditing) {
        super(owner);

        const update = () => {
            const rm = computeCzmModelMatrix({
                rotation: [this.sceneObject.selfRotation[0], this.sceneObject.selfRotation[1], 0],
            });
            if (!rm) {
                throw new Error('PitchPlane: rm is undefined');
            };
            const m = computeCzmModelMatrix({
                position: this.sceneObject.position,
                rotation: this.sceneObject.rotation,
                localModelMatrix: Cesium.Matrix4.toArray(rm) as ESJNativeNumber16,
            });
            this._valid = !!m;
            if (!m) return;
            {
                const v = this._normal;
                v.x = -m[4];
                v.y = -m[5];
                v.z = -m[6];
            }
            {
                const v = this._origin;
                v.x = m[8];
                v.y = m[9];
                v.z = m[10];
            }
        };
        update();
        this.dispose(this.sceneObject.positionChanged.disposableOn(update));
        this.dispose(this.sceneObject.rotationChanged.disposableOn(update));
        this.dispose(this.sceneObject.selfRotationChanged.disposableOn(update));
    }
}